/*
 * Copyright 2011-2012 Rivoli team
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.googlecode.rivoli.reader.aluminum.library

import com.googlecode.aluminumproject.annotations.Ignored
import com.googlecode.aluminumproject.context.Context
import com.googlecode.aluminumproject.libraries.AbstractLibraryElement
import com.googlecode.aluminumproject.libraries.actions.AbstractAction
import com.googlecode.aluminumproject.libraries.actions.ActionException
import com.googlecode.aluminumproject.libraries.actions.ActionFactory
import com.googlecode.aluminumproject.libraries.actions.ActionInformation
import com.googlecode.aluminumproject.libraries.actions.ActionParameter
import com.googlecode.aluminumproject.writers.NullWriter
import com.googlecode.aluminumproject.writers.Writer
import com.googlecode.rivoli.model.AttributeDescriptor
import com.googlecode.rivoli.model.Element
import com.googlecode.rivoli.model.Model
import com.googlecode.rivoli.reader.aluminum.AluminumDefinitionReader

@Ignored
class ElementAction extends AbstractAction {
	private String name
	private Map<String, ActionParameter> parameters

	private List<Element> children

	private ElementAction() {
		children = []
	}

	void execute(Context context, Writer writer) {
		Model model = context.getImplicitObject(AluminumDefinitionReader.MODEL)
		Element element = model.createElement(name)

		mapParametersToAttributes(element, context)
		addChildrenFromBody(element, context)

		ElementAction ancestor = findAncestorOfType(ElementAction)

		if (ancestor) {
			ancestor.addChild(element)
		} else {
			writer.write(element)
		}
	}

	private void mapParametersToAttributes(Element element, Context context) {
		parameters.each {String name, ActionParameter parameter ->
			AttributeDescriptor attributeDescriptor = element.descriptor.findAttributeDescriptor(name)

			if (!attributeDescriptor) {
				throw new ActionException("no attribute descriptor named '${name}' exists")
			}

			element.setAttribute(name, parameter.getValue(attributeDescriptor.type, context))
		}
	}

	private void addChildrenFromBody(Element element, Context context) {
		body.invoke(context, new NullWriter())

		children.each {Element child ->
			element.addChild(child)
		}
	}

	private void addChild(Element child) {
		children << child
	}

	static class Factory extends AbstractLibraryElement implements ActionFactory {
		private String name

		final ActionInformation information

		Factory(String name) {
			this.name = name

			information = new ActionInformation(name, [], true)
		}

		ElementAction create(Map<String, ActionParameter> parameters, Context context) {
			new ElementAction(name: name, parameters: parameters)
		}
	}
}